<?php
namespace app\common\tools;

use think\facade\Validate;
use app\common\exception\ThrowException;
class Req
{
    const NOT_METHOD_MSG = 3000001;
    const HOST_INVALID_MSG = 3000002;
    const URL_INVALID_MSG = 3000003;
    const METHOD_LISTS = [
        'get',
        'post',
        'put',
        'delete',
        'patch',
    ];
    protected $host = '';
    /**
     * 构造方法
     * @access public
     * @param  App  $app  应用对象
     */
    protected function __construct(String $host = '')
    {
        $this->host($host);
    }

    /**
     * 启动方法
     * @param array $version
     * @return mixed
     * @throws \Exception
     */
    public static function init(String $host = '')
    {
        return new self($host);
    }

    public function get(String $url, Array $params = [], Array $header = [])
    {
        $url = $this->url($url);
        $headerArray = $this->header($header);
        if (!empty($params)) {
            $params = http_build_query($params);
            $url = strstr($url, '?') ? $url . '&' . $params : $url . '?' . $params;
        }

        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); 
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); 
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl,CURLOPT_HTTPHEADER,$headerArray);
        $output = curl_exec($curl);
        curl_close($curl);
        $output = json_decode($output,true);
        return $output;
    }

    public function post(String $url, Array $params = [], Array $header = [])
    {
        $header['Content-type'] = $header['Content-type'] ?? "application/x-www-form-urlencoded;charset='utf-8'";
        $url = $this->url($url);
        
        if (!empty($params)) {
            if (strstr($header['Content-type'], 'json')) {
                $params  = json_encode($params);
            } else {
                $params = http_build_query($params);
            }
        }
        $header['Content-Length'] = strlen($params);
        $headerArray = $this->header($header);

        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,FALSE);
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
        curl_setopt($curl, CURLOPT_HTTPHEADER,$headerArray);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        //设置cURL允许执行的最长秒数
        curl_setopt($curl, CURLOPT_TIMEOUT, 30); 
        $output = curl_exec($curl);
        curl_close($curl);
        return json_decode($output, true);
    }

    public function put(String $url, Array $params = [], Array $header = [])
    {
        $url = $this->url($url);
        if (!strstr($header['Content-type'], 'json')) {
            $header['Content-type'] = "application/json";
        }

        $headerArray = $this->header($header);
        $params = json_encode($params);
        $curl = curl_init(); //初始化CURL句柄 
        curl_setopt($curl, CURLOPT_URL, $url); //设置请求的URL
        curl_setopt ($curl, CURLOPT_HTTPHEADER, $headerArray);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER,1); //设为TRUE把curl_exec()结果转化为字串，而不是直接输出 
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST,"PUT"); //设置请求方式
        curl_setopt($curl, CURLOPT_POSTFIELDS, $params);//设置提交的字符串
        $output = curl_exec($curl);
        curl_close($curl);
        return json_decode($output,true);
    }

    public function delete(String $url, Array $params = [], Array $header = [])
    {
        $url = $this->url($url);
        if (!strstr($header['Content-type'], 'json')) {
            $header['Content-type'] = "application/json";
        }

        $headerArray = $this->header($header);
        $params  = json_encode($params);
        $curl = curl_init();
        curl_setopt ($curl,CURLOPT_URL,$url);
        curl_setopt ($curl, CURLOPT_HTTPHEADER, $headerArray);
        curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt ($curl, CURLOPT_CUSTOMREQUEST, "DELETE");   
        curl_setopt($curl, CURLOPT_POSTFIELDS,$params);
        $output = curl_exec($curl);
        curl_close($curl);
        return json_decode($output,true);
    }

    public function patch(String $url, Array $params = [], Array $header = [])
    {
        $url = $this->url($url);
        if (!strstr($header['Content-type'], 'json')) {
            $header['Content-type'] = "application/json";
        }

        $headerArray = $this->header($header);
        $params = json_encode($params);
        $curl = curl_init();
        curl_setopt ($curl,CURLOPT_URL,$url);
        curl_setopt ($curl, CURLOPT_HTTPHEADER, $headerArray);
        curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt ($curl, CURLOPT_CUSTOMREQUEST, "PATCH");  
        curl_setopt($curl, CURLOPT_POSTFIELDS,$params);     //20170611修改接口，用/id的方式传递，直接写在url中了
        $output = curl_exec($curl);
        curl_close($curl);
        return json_decode($output);
    }

    public function request(String $method, String $url, Array $params = [], Array $header = [])
    {
        if (!in_array($method, self::METHOD_LISTS)) {
            ThrowException::res(self::NOT_METHOD_MSG);
        }

        return $this->$method($url, $params, $header);
    }

    protected function header(Array $header = [])
    {
        $header['Content-type'] = $header['Content-type'] ?? "application/json";
        $headerArray = [];
        foreach ($header as $key => $val) {
            $headerArray[] = implode(':', [ucfirst($key), $val]);
        }
        
        return $headerArray;
    }

    protected function host(String $host = '')
    {
        if (!($this->checkUrl($host))) {
            ThrowException::res(self::HOST_INVALID_MSG);
        }

        $this->host = $host;
    }

    protected function url(String $url = '')
    {
        if (!empty($this->host) && !stristr($url, $this->host)) {
            $url = $this->host . $url;
        }

        if (!($this->checkUrl($url))) {
            ThrowException::res(self::URL_INVALID_MSG);
        }

        return $url;
    }

    protected function checkUrl(String $url = null)
    {
        $validate = Validate::rule([
            'url'  => 'url',
        ]);

        $data = [
            'url'  => $url,
        ];

        return $validate->check($data);
    }

    public function params()
    {
    }
    
}
